In the ‘SPEI12 - Calculation.R’ script, there are — Checker No.#. These correlate to code chunks below that can be run to check the calculations. These were done through the calculation process and we believe that the code is correct. These are recorded for aid / subsequent checks.

Questions

# Load in a shapefile of the UK to check whether the output looks nice over the UK
coast <- readOGR(dsn="I:/GIS Data", layer = "high_water_polyline - simplified")
Discarded datum OSGB_1936 in Proj4 definition: +proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +units=m +no_defs
OGR data source with driver: ESRI Shapefile 
Source: "I:\GIS Data", layer: "high_water_polyline - simplified"
with 1 features
It has 1 fields

Checker 1

image(pet[,,12]) # > Produces plot of UK, correct orientation.


# With better plotting:
x = 90; levelplot(pet[,,x], col.regions = terrain.colors(100), at=seq(0, (2/3)*max(pet[,,x]), length.out=12))


# For 10 years:
levelplot(rowSums(pet[,,12:(12*10)], dims = 2), col.regions = terrain.colors(100))

Checker 2

image(UK_mask_full_extent) # > Produces plot of UK, correct orientation.

dim(UK_mask_full_extent)
[1]  82 112

Checker 3

image(uk_mask_raster) # > Produces plot of UK, correct orientation.

image(pet[,,12])

Checker 4

image(pet[,,1]) # > Correct orientation

Checker 5

image(uk_mask_raster) # > Produces plot of UK, correct orientation.

Checker 6

image(UK_mask) # > Produces plot of UK, correct orientation.

Everything should now be in the same orientation, everything is cropped. UK_mask is matrix, PET/PR cropped are arrays, uk_mask_raster is raster uk_mask_raster lists rows then columns, others are columns then rows

Checker 7

image(pr[,,1])

image(pet_masked[,,1])

x = 30; levelplot(pr_masked[,,x], col.regions = terrain.colors(100),
                  at=seq(0.1, max(pr_masked[,,x]), length.out=12))

Checker 8

plot(cumsum(colSums(pr_masked, dims = 2)), type = "l")
lines(cumsum(colSums(pet_masked, dims = 2)), col = 2)
lines(cumsum(colSums(climate_balance_daily, dims = 2)), col = 3)

Checker 9

climate_balance_monthy_map <-
  array(climate_balance_monthy,
        dim=c(dim(climate_balance_monthy)[1], # months
              dim(climate_balance_daily)[1], # columns (Easting)
              dim(climate_balance_daily)[2])) # rows (Northing)
climate_balance_monthy_map <- aperm(climate_balance_monthy_map, c(2, 3, 1))

levelplot(climate_balance_monthy_map[,,30],
          col.regions = terrain.colors(100),
          at=seq(min(climate_balance_monthy_map[,,30], na.rm = T),
                 max(climate_balance_monthy_map[,,30], na.rm = T),
                 length.out=12))

Checker 10

dim(spei_map)  #  image(spei_map[,,120])
[1]   57  104 1200
custom_cols = c(
  colorRampPalette(c("green", "white"))(50),
  colorRampPalette("white")(1),
  colorRampPalette(c("white","red"))(50))

# Set final timestep to check up to: 
y = 49
# Get max, symmetrical data ranges:
range_val = range(climate_balance_monthy_map[,,(y-12):y], na.rm = T)
range_val = max(abs(range_val))
# Run through the 12 preceding timesteps:
for(m in (y-12):y){
  # Plot the climate balance for those months:
    x = climate_balance_monthy_map[,,m]
    print(
      levelplot(x, 
                col.regions = custom_cols,
                at=seq(-range_val, range_val, length.out=101)))
}

# Now plot the corresponding SPEI map month - these should match up:
levelplot(spei_map[,,y], col.regions = custom_cols, at=seq(-2, 2, length.out=100), main="SPEI")

cbal_average = apply(climate_balance_monthy_map[,,(y-12):y], c(1,2), mean)
levelplot(cbal_average, col.regions = custom_cols, at=seq(-80, 230, length.out=101), main = "12-month Climate Balance")

This seems to show that the SPEI map is almost the inverse of the Climate Balance, which is unexpected.

plot_ly(x = 1:120, y = pr_masked[33,40,1:120], type = 'scatter', mode = 'lines', name ='pr') %>%
  add_lines(x = 1:120, y = pet_masked[33,40,1:120], type = 'scatter', mode = 'lines', name ='pet') %>%
  add_lines(x = 1:120, y = climate_balance_monthy_map[33,40,1:120], type = 'scatter', mode = 'lines', name ='bal')
# Look at how the climate balance, climate balance moving average and SPEI12 compare:
a=16 ; b=62 ; bal_ma_1 = ma(climate_balance_monthy_map[a,b,1:120], 12)
c=25 ; d=33 ; bal_ma_2 = ma(climate_balance_monthy_map[c,d,1:120], 12)

plot_ly(x = 1:120, y = climate_balance_monthy_map[a,b,1:120], type = 'scatter', mode = 'lines', name ='BAL 1') %>%
  add_lines(x = 1:120, y = bal_ma_1, type = 'scatter', mode = 'lines', name ='BAL 1 MA') %>%
  add_lines(x = 1:120, y = spei_map[a,b,1:120], type = 'scatter', mode = 'lines', name ='SPEI-12 1', yaxis = "y2") %>%
  
  add_lines(x = 1:120, y = climate_balance_monthy_map[c,d,1:120], type = 'scatter', mode = 'lines', name ='BAL 2') %>%
  add_lines(x = 1:120, y = bal_ma_2, type = 'scatter', mode = 'lines', name ='BAL 2 MA') %>%
  add_lines(x = 1:120, y = spei_map[c,d,1:120], type = 'scatter', mode = 'lines', name ='SPEI-12 2', yaxis = "y2") %>%
  
  layout(yaxis2 = list(side='right', overlaying='y'))

The Climate balance 12 month rolling average matches VERY closely to the relative SPEI12 value.

So the Climate balance moving average and the SPEI correlate very strongly. But the maps 100% don’t correlate between the two.

If we plot the Climate balance moving average and SPEI for 2 cells then, which each correlates on a cell level, we get big differences in climate balance but don’t equate to the same differences in SPEI.

So, maybe SPEI just doesn’t correlate spatially with climate balance? It stated above that SPEI is a measure of the number of standard deviations from the norm - so it would make sense that each cell is its own unit and a low climate balance in one place may not reflect a low SPEI, if that variation in climate balance is not unusual…

If it is a pixel that is regularly wet, and the drought index is defined as a distance in standard deviations from a mean, then the threshold for the wet pixel being in drought would be a ‘wetter’ threshold than a dry pixel, if that makes sense. So the climate balance would be wetter

Google says: “magnitude of drought conditions with respect to normal conditions”

Checker 11

Plot the SPEI along with a line showing the clasification of drought.

# Create an indicator array showing droughts (SPEI < threshold)
# Plot SPEI time series scatter plot(1 cell)
plot(ts(spei_map[30,25,]))#, title="Average SPEI @ [30,25,:]")
abline(h=threshold, col="red")


plot(ma(climate_balance_monthy_map[30, 25,]), col = "blue")

Plot some maps showing the climate data averaged over the whole of the UK

pr_plot = flip(t(raster(pr_masked[,,480], crs=27700)))
pet_plot = flip(t(raster(pet_masked[,,480], crs=27700)))
cb_plot = climate_balance_daily[,,480]
cb_plot[!UK_mask] = NA
cb_plot = flip(t(raster(cb_plot, crs=27700)))

extent(pr_plot) = grid_extent
extent(pet_plot) = grid_extent
extent(cb_plot) = grid_extent

# Create Plots:
par(mfrow=c(1, 3), mar = c(3,3,5,2))
cuts = c(-5:20) #set breaks
pal <- c(colorRampPalette(c("red","white"))(4),
         colorRampPalette(c("white","blue"))(20))

plot(pr_plot, main="Precipitation\n(mm/day)",
     breaks=cuts, col = pal,
     legend.args=list(text="", side=4, font=2, line=2, cex=1))
plot(coast, add=TRUE)

plot(pet_plot, main="Potential Evapotranspiration\n(mm/day)", 
     breaks=cuts, col = pal,
     legend.args=list(text="", side=4, line=2.5, cex.axis=3))
plot(coast, add=TRUE)
  
plot(cb_plot, main="Climate Balance\n(mm/day)", 
     breaks=cuts, col = pal,
     legend.args=list(text="", side=4, font=4, line=2.5, 
                      cex.lab=3, cex.axis=3, cex.main=3, cex.sub=3))
plot(coast, add=TRUE)

Plot some maps showing the overall probability, mean and max drought length for the UK.

# Calculate the probability that a month is in drought for the whole time series:
probability_of_drought_grid <- rowMeans(drought_indicator, na.rm=T, dim=2)

# Probability that a month is a drought:
drought_probability_raster <- flip(t(raster(probability_of_drought_grid, crs=27700)))
extent(drought_probability_raster) = grid_extent

# Average drought length for each pixel over the data:
mean_drought_length <- apply(drought_indicator, c(1,2), length_stats, mean)
mean_drought_length_raster <- flip(t(raster(mean_drought_length, crs=27700)))
extent(mean_drought_length_raster) <- grid_extent

# Maximum drought length for each pixel over the data:
max_drought_length <- apply(drought_indicator, c(1,2), length_stats, max)
max_drought_length_raster <- flip(t(raster(max_drought_length, crs=27700)))
extent(max_drought_length_raster) <- grid_extent

# Create Plots:
par(mfrow=c(1, 3), mar = c(6,5,5,2))

plot(drought_probability_raster,
     main="Probability a month\nis in drought", 
     legend.args=list(text="", side=4, font=2, line=2.5, cex=2))
plot(coast, add=TRUE)

plot(mean_drought_length_raster, 
     main="Average drought length", 
     legend.args=list(text="Months", side=4, font=2, line=2.5, cex=0.8))
plot(coast, add=TRUE)

plot(max_drought_length_raster, 
     main="Maximum drought length", 
     legend.args=list(text="Months", side=4, font=2, line=2.5, cex=0.8))
plot(coast, add=TRUE)

LS0tDQp0aXRsZTogIlNQRUkxMiAtIENhbGN1bGF0aW9uIENoZWNrZXIiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpJbiB0aGUgJ1NQRUkxMiAtIENhbGN1bGF0aW9uLlInIHNjcmlwdCwgdGhlcmUgYXJlIC0tLSBDaGVja2VyIE5vLiMuDQpUaGVzZSBjb3JyZWxhdGUgdG8gY29kZSBjaHVua3MgYmVsb3cgdGhhdCBjYW4gYmUgcnVuIHRvIGNoZWNrIHRoZSBjYWxjdWxhdGlvbnMuDQpUaGVzZSB3ZXJlIGRvbmUgdGhyb3VnaCB0aGUgY2FsY3VsYXRpb24gcHJvY2VzcyBhbmQgd2UgYmVsaWV2ZSB0aGF0IHRoZSBjb2RlDQppcyBjb3JyZWN0LiBUaGVzZSBhcmUgcmVjb3JkZWQgZm9yIGFpZCAvIHN1YnNlcXVlbnQgY2hlY2tzLg0KDQojIyMgUXVlc3Rpb25zDQogIC0gRG8gd2UgbmVlZCB0byBoYXZlIGJpYXMgY29ycmVjdGVkIHRoZSBkYXRhPw0KICAtIERvIHdlIG5lZWQgdG8gdXNlIGEgcmVmZXJlbmNlIHBlcmlvZCBmb3IgdGhlIFNQRUkgKGJhc2VsaW5lIHBlcmlvZCk/DQogIC0gRG8gcmVxdWVzdGVycyB1bmRlcnN0YW5kIFNQRUkgMTI/DQoNCmBgYHtyfQ0KIyBMb2FkIGluIGEgc2hhcGVmaWxlIG9mIHRoZSBVSyB0byBjaGVjayB3aGV0aGVyIHRoZSBvdXRwdXQgbG9va3MgbmljZSBvdmVyIHRoZSBVSw0KY29hc3QgPC0gcmVhZE9HUihkc249Ikk6L0dJUyBEYXRhIiwgbGF5ZXIgPSAiaGlnaF93YXRlcl9wb2x5bGluZSAtIHNpbXBsaWZpZWQiKQ0KYGBgDQoNCg0KIyBDaGVja2VyIDENCmBgYHtyIDF9DQppbWFnZShwZXRbLCwxMl0pICMgPiBQcm9kdWNlcyBwbG90IG9mIFVLLCBjb3JyZWN0IG9yaWVudGF0aW9uLg0KDQojIFdpdGggYmV0dGVyIHBsb3R0aW5nOg0KeCA9IDkwOyBsZXZlbHBsb3QocGV0WywseF0sIGNvbC5yZWdpb25zID0gdGVycmFpbi5jb2xvcnMoMTAwKSwgYXQ9c2VxKDAsICgyLzMpKm1heChwZXRbLCx4XSksIGxlbmd0aC5vdXQ9MTIpKQ0KDQojIEZvciAxMCB5ZWFyczoNCmxldmVscGxvdChyb3dTdW1zKHBldFssLDEyOigxMioxMCldLCBkaW1zID0gMiksIGNvbC5yZWdpb25zID0gdGVycmFpbi5jb2xvcnMoMTAwKSkNCmBgYA0KDQojIENoZWNrZXIgMg0KYGBge3IgMn0NCmltYWdlKFVLX21hc2tfZnVsbF9leHRlbnQpICMgPiBQcm9kdWNlcyBwbG90IG9mIFVLLCBjb3JyZWN0IG9yaWVudGF0aW9uLg0KZGltKFVLX21hc2tfZnVsbF9leHRlbnQpDQpgYGANCg0KIyBDaGVja2VyIDMNCmBgYHtyIDN9DQppbWFnZSh1a19tYXNrX3Jhc3RlcikgIyA+IFByb2R1Y2VzIHBsb3Qgb2YgVUssIGNvcnJlY3Qgb3JpZW50YXRpb24uDQppbWFnZShwZXRbLCwxMl0pDQpgYGANCg0KIyBDaGVja2VyIDQNCmBgYHtyIDR9DQppbWFnZShwZXRbLCwxXSkgIyA+IENvcnJlY3Qgb3JpZW50YXRpb24NCmBgYA0KDQojIENoZWNrZXIgNQ0KYGBge3IgNX0NCmltYWdlKHVrX21hc2tfcmFzdGVyKSAjID4gUHJvZHVjZXMgcGxvdCBvZiBVSywgY29ycmVjdCBvcmllbnRhdGlvbi4NCmBgYA0KDQojIENoZWNrZXIgNg0KYGBge3IgNn0NCmltYWdlKFVLX21hc2spICMgPiBQcm9kdWNlcyBwbG90IG9mIFVLLCBjb3JyZWN0IG9yaWVudGF0aW9uLg0KYGBgDQoNCkV2ZXJ5dGhpbmcgc2hvdWxkIG5vdyBiZSBpbiB0aGUgc2FtZSBvcmllbnRhdGlvbiwgZXZlcnl0aGluZyBpcyBjcm9wcGVkLg0KVUtfbWFzayBpcyBtYXRyaXgsIFBFVC9QUiBjcm9wcGVkIGFyZSBhcnJheXMsIHVrX21hc2tfcmFzdGVyIGlzIHJhc3Rlcg0KdWtfbWFza19yYXN0ZXIgbGlzdHMgcm93cyB0aGVuIGNvbHVtbnMsIG90aGVycyBhcmUgY29sdW1ucyB0aGVuIHJvd3MNCg0KIyBDaGVja2VyIDcNCmBgYHtyIDd9DQppbWFnZShwclssLDFdKQ0KaW1hZ2UocGV0X21hc2tlZFssLDFdKQ0KeCA9IDMwOyBsZXZlbHBsb3QocHJfbWFza2VkWywseF0sIGNvbC5yZWdpb25zID0gdGVycmFpbi5jb2xvcnMoMTAwKSwNCiAgICAgICAgICAgICAgICAgIGF0PXNlcSgwLjEsIG1heChwcl9tYXNrZWRbLCx4XSksIGxlbmd0aC5vdXQ9MTIpKQ0KYGBgDQoNCiMgQ2hlY2tlciA4DQpgYGB7ciA4fQ0KcGxvdChjdW1zdW0oY29sU3Vtcyhwcl9tYXNrZWQsIGRpbXMgPSAyKSksIHR5cGUgPSAibCIpDQpsaW5lcyhjdW1zdW0oY29sU3VtcyhwZXRfbWFza2VkLCBkaW1zID0gMikpLCBjb2wgPSAyKQ0KbGluZXMoY3Vtc3VtKGNvbFN1bXMoY2xpbWF0ZV9iYWxhbmNlX2RhaWx5LCBkaW1zID0gMikpLCBjb2wgPSAzKQ0KYGBgDQoNCiMgQ2hlY2tlciA5DQpgYGB7ciA5fQ0KY2xpbWF0ZV9iYWxhbmNlX21vbnRoeV9tYXAgPC0NCiAgYXJyYXkoY2xpbWF0ZV9iYWxhbmNlX21vbnRoeSwNCiAgICAgICAgZGltPWMoZGltKGNsaW1hdGVfYmFsYW5jZV9tb250aHkpWzFdLCAjIG1vbnRocw0KICAgICAgICAgICAgICBkaW0oY2xpbWF0ZV9iYWxhbmNlX2RhaWx5KVsxXSwgIyBjb2x1bW5zIChFYXN0aW5nKQ0KICAgICAgICAgICAgICBkaW0oY2xpbWF0ZV9iYWxhbmNlX2RhaWx5KVsyXSkpICMgcm93cyAoTm9ydGhpbmcpDQpjbGltYXRlX2JhbGFuY2VfbW9udGh5X21hcCA8LSBhcGVybShjbGltYXRlX2JhbGFuY2VfbW9udGh5X21hcCwgYygyLCAzLCAxKSkNCg0KbGV2ZWxwbG90KGNsaW1hdGVfYmFsYW5jZV9tb250aHlfbWFwWywsMzBdLA0KICAgICAgICAgIGNvbC5yZWdpb25zID0gdGVycmFpbi5jb2xvcnMoMTAwKSwNCiAgICAgICAgICBhdD1zZXEobWluKGNsaW1hdGVfYmFsYW5jZV9tb250aHlfbWFwWywsMzBdLCBuYS5ybSA9IFQpLA0KICAgICAgICAgICAgICAgICBtYXgoY2xpbWF0ZV9iYWxhbmNlX21vbnRoeV9tYXBbLCwzMF0sIG5hLnJtID0gVCksDQogICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQ9MTIpKQ0KYGBgDQoNCiMgQ2hlY2tlciAxMA0KYGBge3IgMTBhfQ0KZGltKHNwZWlfbWFwKSAgIyAgaW1hZ2Uoc3BlaV9tYXBbLCwxMjBdKQ0KYGBgDQoNCg0KYGBge3IgMTBifQ0KY3VzdG9tX2NvbHMgPSBjKA0KICBjb2xvclJhbXBQYWxldHRlKGMoImdyZWVuIiwgIndoaXRlIikpKDUwKSwNCiAgY29sb3JSYW1wUGFsZXR0ZSgid2hpdGUiKSgxKSwNCiAgY29sb3JSYW1wUGFsZXR0ZShjKCJ3aGl0ZSIsInJlZCIpKSg1MCkpDQoNCiMgU2V0IGZpbmFsIHRpbWVzdGVwIHRvIGNoZWNrIHVwIHRvOiANCnkgPSA0OQ0KIyBHZXQgbWF4LCBzeW1tZXRyaWNhbCBkYXRhIHJhbmdlczoNCnJhbmdlX3ZhbCA9IHJhbmdlKGNsaW1hdGVfYmFsYW5jZV9tb250aHlfbWFwWywsKHktMTIpOnldLCBuYS5ybSA9IFQpDQpyYW5nZV92YWwgPSBtYXgoYWJzKHJhbmdlX3ZhbCkpDQojIFJ1biB0aHJvdWdoIHRoZSAxMiBwcmVjZWRpbmcgdGltZXN0ZXBzOg0KZm9yKG0gaW4gKHktMTIpOnkpew0KICAjIFBsb3QgdGhlIGNsaW1hdGUgYmFsYW5jZSBmb3IgdGhvc2UgbW9udGhzOg0KICAgIHggPSBjbGltYXRlX2JhbGFuY2VfbW9udGh5X21hcFssLG1dDQogICAgcHJpbnQoDQogICAgICBsZXZlbHBsb3QoeCwgDQogICAgICAgICAgICAgICAgY29sLnJlZ2lvbnMgPSBjdXN0b21fY29scywNCiAgICAgICAgICAgICAgICBhdD1zZXEoLXJhbmdlX3ZhbCwgcmFuZ2VfdmFsLCBsZW5ndGgub3V0PTEwMSkpKQ0KfQ0KYGBgDQoNCg0KYGBge3IgMTBjfQ0KIyBOb3cgcGxvdCB0aGUgY29ycmVzcG9uZGluZyBTUEVJIG1hcCBtb250aCAtIHRoZXNlIHNob3VsZCBtYXRjaCB1cDoNCmxldmVscGxvdChzcGVpX21hcFssLHldLCBjb2wucmVnaW9ucyA9IGN1c3RvbV9jb2xzLCBhdD1zZXEoLTIsIDIsIGxlbmd0aC5vdXQ9MTAwKSwgbWFpbj0iU1BFSSIpDQpjYmFsX2F2ZXJhZ2UgPSBhcHBseShjbGltYXRlX2JhbGFuY2VfbW9udGh5X21hcFssLCh5LTEyKTp5XSwgYygxLDIpLCBtZWFuKQ0KbGV2ZWxwbG90KGNiYWxfYXZlcmFnZSwgY29sLnJlZ2lvbnMgPSBjdXN0b21fY29scywgYXQ9c2VxKC04MCwgMjMwLCBsZW5ndGgub3V0PTEwMSksIG1haW4gPSAiMTItbW9udGggQ2xpbWF0ZSBCYWxhbmNlIikNCmBgYA0KVGhpcyBzZWVtcyB0byBzaG93IHRoYXQgdGhlIFNQRUkgbWFwIGlzIGFsbW9zdCB0aGUgaW52ZXJzZSBvZiB0aGUgQ2xpbWF0ZSBCYWxhbmNlLCB3aGljaCBpcyB1bmV4cGVjdGVkLg0KDQpgYGB7ciAxMGR9DQpwbG90X2x5KHggPSAxOjEyMCwgeSA9IHByX21hc2tlZFszMyw0MCwxOjEyMF0sIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMnLCBuYW1lID0ncHInKSAlPiUNCiAgYWRkX2xpbmVzKHggPSAxOjEyMCwgeSA9IHBldF9tYXNrZWRbMzMsNDAsMToxMjBdLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzJywgbmFtZSA9J3BldCcpICU+JQ0KICBhZGRfbGluZXMoeCA9IDE6MTIwLCB5ID0gY2xpbWF0ZV9iYWxhbmNlX21vbnRoeV9tYXBbMzMsNDAsMToxMjBdLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzJywgbmFtZSA9J2JhbCcpDQpgYGANCg0KDQpgYGB7ciAxMGV9DQojIExvb2sgYXQgaG93IHRoZSBjbGltYXRlIGJhbGFuY2UsIGNsaW1hdGUgYmFsYW5jZSBtb3ZpbmcgYXZlcmFnZSBhbmQgU1BFSTEyIGNvbXBhcmU6DQphPTE2IDsgYj02MiA7IGJhbF9tYV8xID0gbWEoY2xpbWF0ZV9iYWxhbmNlX21vbnRoeV9tYXBbYSxiLDE6MTIwXSwgMTIpDQpjPTI1IDsgZD0zMyA7IGJhbF9tYV8yID0gbWEoY2xpbWF0ZV9iYWxhbmNlX21vbnRoeV9tYXBbYyxkLDE6MTIwXSwgMTIpDQoNCnBsb3RfbHkoeCA9IDE6MTIwLCB5ID0gY2xpbWF0ZV9iYWxhbmNlX21vbnRoeV9tYXBbYSxiLDE6MTIwXSwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcycsIG5hbWUgPSdCQUwgMScpICU+JQ0KICBhZGRfbGluZXMoeCA9IDE6MTIwLCB5ID0gYmFsX21hXzEsIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMnLCBuYW1lID0nQkFMIDEgTUEnKSAlPiUNCiAgYWRkX2xpbmVzKHggPSAxOjEyMCwgeSA9IHNwZWlfbWFwW2EsYiwxOjEyMF0sIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMnLCBuYW1lID0nU1BFSS0xMiAxJywgeWF4aXMgPSAieTIiKSAlPiUNCiAgDQogIGFkZF9saW5lcyh4ID0gMToxMjAsIHkgPSBjbGltYXRlX2JhbGFuY2VfbW9udGh5X21hcFtjLGQsMToxMjBdLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzJywgbmFtZSA9J0JBTCAyJykgJT4lDQogIGFkZF9saW5lcyh4ID0gMToxMjAsIHkgPSBiYWxfbWFfMiwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcycsIG5hbWUgPSdCQUwgMiBNQScpICU+JQ0KICBhZGRfbGluZXMoeCA9IDE6MTIwLCB5ID0gc3BlaV9tYXBbYyxkLDE6MTIwXSwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcycsIG5hbWUgPSdTUEVJLTEyIDInLCB5YXhpcyA9ICJ5MiIpICU+JQ0KICANCiAgbGF5b3V0KHlheGlzMiA9IGxpc3Qoc2lkZT0ncmlnaHQnLCBvdmVybGF5aW5nPSd5JykpDQpgYGANClRoZSBDbGltYXRlIGJhbGFuY2UgMTIgbW9udGggcm9sbGluZyBhdmVyYWdlIG1hdGNoZXMgVkVSWSBjbG9zZWx5IHRvIHRoZSByZWxhdGl2ZSBTUEVJMTIgdmFsdWUuDQoNClNvIHRoZSBDbGltYXRlIGJhbGFuY2UgbW92aW5nIGF2ZXJhZ2UgYW5kIHRoZSBTUEVJIGNvcnJlbGF0ZSB2ZXJ5IHN0cm9uZ2x5LiBCdXQgdGhlIG1hcHMgMTAwJSBkb24ndCBjb3JyZWxhdGUgYmV0d2VlbiB0aGUgdHdvLg0KDQpJZiB3ZSBwbG90IHRoZSBDbGltYXRlIGJhbGFuY2UgbW92aW5nIGF2ZXJhZ2UgYW5kIFNQRUkgZm9yIDIgY2VsbHMgdGhlbiwgd2hpY2ggZWFjaCBjb3JyZWxhdGVzIG9uIGEgY2VsbCBsZXZlbCwgd2UgZ2V0IGJpZyBkaWZmZXJlbmNlcyBpbiBjbGltYXRlIGJhbGFuY2UgYnV0IGRvbid0IGVxdWF0ZSB0byB0aGUgc2FtZSBkaWZmZXJlbmNlcyBpbiBTUEVJLg0KDQpTbywgbWF5YmUgU1BFSSBqdXN0IGRvZXNuJ3QgY29ycmVsYXRlIHNwYXRpYWxseSB3aXRoIGNsaW1hdGUgYmFsYW5jZT8gSXQgc3RhdGVkIGFib3ZlIHRoYXQgU1BFSSBpcyBhIG1lYXN1cmUgb2YgdGhlIG51bWJlciBvZiBzdGFuZGFyZCBkZXZpYXRpb25zIGZyb20gdGhlIG5vcm0gLSBzbyBpdCB3b3VsZCBtYWtlIHNlbnNlIHRoYXQgZWFjaCBjZWxsIGlzIGl0cyBvd24gdW5pdCBhbmQgYSBsb3cgY2xpbWF0ZSBiYWxhbmNlIGluIG9uZSBwbGFjZSBtYXkgbm90IHJlZmxlY3QgYSBsb3cgU1BFSSwgaWYgdGhhdCB2YXJpYXRpb24gaW4gY2xpbWF0ZSBiYWxhbmNlIGlzIG5vdCB1bnVzdWFsLi4uDQoNCklmIGl0IGlzIGEgcGl4ZWwgdGhhdCBpcyByZWd1bGFybHkgd2V0LCBhbmQgdGhlIGRyb3VnaHQgaW5kZXggaXMgZGVmaW5lZCBhcyBhIGRpc3RhbmNlIGluIHN0YW5kYXJkIGRldmlhdGlvbnMgZnJvbSBhIG1lYW4sIHRoZW4gdGhlIHRocmVzaG9sZCBmb3IgdGhlIHdldCBwaXhlbCBiZWluZyBpbiBkcm91Z2h0IHdvdWxkIGJlIGEgJ3dldHRlcicgdGhyZXNob2xkIHRoYW4gYSBkcnkgcGl4ZWwsIGlmIHRoYXQgbWFrZXMgc2Vuc2UuIFNvIHRoZSBjbGltYXRlIGJhbGFuY2Ugd291bGQgYmUgd2V0dGVyDQoNCkdvb2dsZSBzYXlzOiAibWFnbml0dWRlIG9mIGRyb3VnaHQgY29uZGl0aW9ucyB3aXRoIHJlc3BlY3QgdG8gbm9ybWFsIGNvbmRpdGlvbnMiDQoNCiMgQ2hlY2tlciAxMQ0KUGxvdCB0aGUgU1BFSSBhbG9uZyB3aXRoIGEgbGluZSBzaG93aW5nIHRoZSBjbGFzaWZpY2F0aW9uIG9mIGRyb3VnaHQuDQpgYGB7ciAxMWF9DQpwbG90KHRzKHNwZWlfbWFwWzMwLDI1LF0pKSMsIHRpdGxlPSJBdmVyYWdlIFNQRUkgQCBbMzAsMjUsOl0iKQ0KYWJsaW5lKGg9dGhyZXNob2xkLCBjb2w9InJlZCIpDQoNCnBsb3QobWEoY2xpbWF0ZV9iYWxhbmNlX21vbnRoeV9tYXBbMzAsIDI1LF0pLCBjb2wgPSAiYmx1ZSIpDQpgYGANCg0KIyBQbG90IHNvbWUgbWFwcyBzaG93aW5nIHRoZSBjbGltYXRlIGRhdGEgYXZlcmFnZWQgb3ZlciB0aGUgd2hvbGUgb2YgdGhlIFVLDQpgYGB7ciAxMWJ9DQpwcl9wbG90ID0gZmxpcCh0KHJhc3Rlcihwcl9tYXNrZWRbLCw0ODBdLCBjcnM9Mjc3MDApKSkNCnBldF9wbG90ID0gZmxpcCh0KHJhc3RlcihwZXRfbWFza2VkWywsNDgwXSwgY3JzPTI3NzAwKSkpDQpjYl9wbG90ID0gY2xpbWF0ZV9iYWxhbmNlX2RhaWx5WywsNDgwXQ0KY2JfcGxvdFshVUtfbWFza10gPSBOQQ0KY2JfcGxvdCA9IGZsaXAodChyYXN0ZXIoY2JfcGxvdCwgY3JzPTI3NzAwKSkpDQoNCmV4dGVudChwcl9wbG90KSA9IGdyaWRfZXh0ZW50DQpleHRlbnQocGV0X3Bsb3QpID0gZ3JpZF9leHRlbnQNCmV4dGVudChjYl9wbG90KSA9IGdyaWRfZXh0ZW50DQoNCiMgQ3JlYXRlIFBsb3RzOg0KcGFyKG1mcm93PWMoMSwgMyksIG1hciA9IGMoMywzLDUsMikpDQpjdXRzID0gYygtNToyMCkgI3NldCBicmVha3MNCnBhbCA8LSBjKGNvbG9yUmFtcFBhbGV0dGUoYygicmVkIiwid2hpdGUiKSkoNCksDQogICAgICAgICBjb2xvclJhbXBQYWxldHRlKGMoIndoaXRlIiwiYmx1ZSIpKSgyMCkpDQoNCnBsb3QocHJfcGxvdCwgbWFpbj0iUHJlY2lwaXRhdGlvblxuKG1tL2RheSkiLA0KICAgICBicmVha3M9Y3V0cywgY29sID0gcGFsLA0KICAgICBsZWdlbmQuYXJncz1saXN0KHRleHQ9IiIsIHNpZGU9NCwgZm9udD0yLCBsaW5lPTIsIGNleD0xKSkNCnBsb3QoY29hc3QsIGFkZD1UUlVFKQ0KDQpwbG90KHBldF9wbG90LCBtYWluPSJQb3RlbnRpYWwgRXZhcG90cmFuc3BpcmF0aW9uXG4obW0vZGF5KSIsIA0KICAgICBicmVha3M9Y3V0cywgY29sID0gcGFsLA0KICAgICBsZWdlbmQuYXJncz1saXN0KHRleHQ9IiIsIHNpZGU9NCwgbGluZT0yLjUsIGNleC5heGlzPTMpKQ0KcGxvdChjb2FzdCwgYWRkPVRSVUUpDQogIA0KcGxvdChjYl9wbG90LCBtYWluPSJDbGltYXRlIEJhbGFuY2VcbihtbS9kYXkpIiwgDQogICAgIGJyZWFrcz1jdXRzLCBjb2wgPSBwYWwsDQogICAgIGxlZ2VuZC5hcmdzPWxpc3QodGV4dD0iIiwgc2lkZT00LCBmb250PTQsIGxpbmU9Mi41LCANCiAgICAgICAgICAgICAgICAgICAgICBjZXgubGFiPTMsIGNleC5heGlzPTMsIGNleC5tYWluPTMsIGNleC5zdWI9MykpDQpwbG90KGNvYXN0LCBhZGQ9VFJVRSkNCmBgYA0KDQpQbG90IHNvbWUgbWFwcyBzaG93aW5nIHRoZSBvdmVyYWxsIHByb2JhYmlsaXR5LCBtZWFuIGFuZCBtYXggZHJvdWdodCBsZW5ndGggZm9yIHRoZSBVSy4NCmBgYHtyIDExY30NCiMgQ2FsY3VsYXRlIHRoZSBwcm9iYWJpbGl0eSB0aGF0IGEgbW9udGggaXMgaW4gZHJvdWdodCBmb3IgdGhlIHdob2xlIHRpbWUgc2VyaWVzOg0KcHJvYmFiaWxpdHlfb2ZfZHJvdWdodF9ncmlkIDwtIHJvd01lYW5zKGRyb3VnaHRfaW5kaWNhdG9yLCBuYS5ybT1ULCBkaW09MikNCg0KIyBQcm9iYWJpbGl0eSB0aGF0IGEgbW9udGggaXMgYSBkcm91Z2h0Og0KZHJvdWdodF9wcm9iYWJpbGl0eV9yYXN0ZXIgPC0gZmxpcCh0KHJhc3Rlcihwcm9iYWJpbGl0eV9vZl9kcm91Z2h0X2dyaWQsIGNycz0yNzcwMCkpKQ0KZXh0ZW50KGRyb3VnaHRfcHJvYmFiaWxpdHlfcmFzdGVyKSA9IGdyaWRfZXh0ZW50DQoNCiMgQXZlcmFnZSBkcm91Z2h0IGxlbmd0aCBmb3IgZWFjaCBwaXhlbCBvdmVyIHRoZSBkYXRhOg0KbWVhbl9kcm91Z2h0X2xlbmd0aCA8LSBhcHBseShkcm91Z2h0X2luZGljYXRvciwgYygxLDIpLCBsZW5ndGhfc3RhdHMsIG1lYW4pDQptZWFuX2Ryb3VnaHRfbGVuZ3RoX3Jhc3RlciA8LSBmbGlwKHQocmFzdGVyKG1lYW5fZHJvdWdodF9sZW5ndGgsIGNycz0yNzcwMCkpKQ0KZXh0ZW50KG1lYW5fZHJvdWdodF9sZW5ndGhfcmFzdGVyKSA8LSBncmlkX2V4dGVudA0KDQojIE1heGltdW0gZHJvdWdodCBsZW5ndGggZm9yIGVhY2ggcGl4ZWwgb3ZlciB0aGUgZGF0YToNCm1heF9kcm91Z2h0X2xlbmd0aCA8LSBhcHBseShkcm91Z2h0X2luZGljYXRvciwgYygxLDIpLCBsZW5ndGhfc3RhdHMsIG1heCkNCm1heF9kcm91Z2h0X2xlbmd0aF9yYXN0ZXIgPC0gZmxpcCh0KHJhc3RlcihtYXhfZHJvdWdodF9sZW5ndGgsIGNycz0yNzcwMCkpKQ0KZXh0ZW50KG1heF9kcm91Z2h0X2xlbmd0aF9yYXN0ZXIpIDwtIGdyaWRfZXh0ZW50DQoNCiMgQ3JlYXRlIFBsb3RzOg0KcGFyKG1mcm93PWMoMSwgMyksIG1hciA9IGMoNiw1LDUsMikpDQoNCnBsb3QoZHJvdWdodF9wcm9iYWJpbGl0eV9yYXN0ZXIsDQogICAgIG1haW49IlByb2JhYmlsaXR5IGEgbW9udGhcbmlzIGluIGRyb3VnaHQiLCANCiAgICAgbGVnZW5kLmFyZ3M9bGlzdCh0ZXh0PSIiLCBzaWRlPTQsIGZvbnQ9MiwgbGluZT0yLjUsIGNleD0yKSkNCnBsb3QoY29hc3QsIGFkZD1UUlVFKQ0KDQpwbG90KG1lYW5fZHJvdWdodF9sZW5ndGhfcmFzdGVyLCANCiAgICAgbWFpbj0iQXZlcmFnZSBkcm91Z2h0IGxlbmd0aCIsIA0KICAgICBsZWdlbmQuYXJncz1saXN0KHRleHQ9Ik1vbnRocyIsIHNpZGU9NCwgZm9udD0yLCBsaW5lPTIuNSwgY2V4PTAuOCkpDQpwbG90KGNvYXN0LCBhZGQ9VFJVRSkNCg0KcGxvdChtYXhfZHJvdWdodF9sZW5ndGhfcmFzdGVyLCANCiAgICAgbWFpbj0iTWF4aW11bSBkcm91Z2h0IGxlbmd0aCIsIA0KICAgICBsZWdlbmQuYXJncz1saXN0KHRleHQ9Ik1vbnRocyIsIHNpZGU9NCwgZm9udD0yLCBsaW5lPTIuNSwgY2V4PTAuOCkpDQpwbG90KGNvYXN0LCBhZGQ9VFJVRSkNCmBgYA0KDQo=